home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-02-03 | 32.5 KB | 1,511 lines |
- Path: xanth!nic.MR.NET!csd4.milw.wisc.edu!leah!itsgw!steinmetz!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v06i023: shadow password routines, part 2
- Message-ID: <47755@uunet.UU.NET>
- Date: 29 Jan 89 21:12:45 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: jfh@hal.CWRU.Edu@convex.UUCP (John F. Haugh II)
- Lines: 1499
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 6, Issue 23
- Submitted-by: jfh@hal.CWRU.Edu@convex.UUCP (John F. Haugh II)
- Archive-name: shadow-2.pt2
-
- [No Subject: line -- biggest violation in the rulebook. How am I supposed
- to know this is multipart ahead of schedule? ++bsa]
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # log.c
- # mail.c
- # shadow.h
- # sulog.c
- # Makefile
- # entry.c
- # obscure.c
- # setup.c
- # sub.c
- # config.h
- # shadow.info
- # pmain.c
- # sulogin.c
- # dialup.h
- # This archive created: Sun Jan 22 22:24:51 1989
- # By: John F. Haugh II (River Parishes Programming, Dallas TX)
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'log.c'
- then
- echo shar: "will not over-write existing file 'log.c'"
- else
- cat << \SHAR_EOF > 'log.c'
- #include <sys/types.h>
- #include <utmp.h>
- #include <pwd.h>
- #include <fcntl.h>
- #include <time.h>
- #include <string.h>
- #include "config.h"
-
- extern struct utmp utent;
- extern struct passwd pwent;
- extern struct lastlog lastlog;
- extern char **environ;
-
- long lseek ();
- time_t time ();
-
- #ifdef LASTLOG
-
- #include "lastlog.h"
-
- void log ()
- {
- int fd;
- long offset;
- struct lastlog newlog;
-
- if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1)
- return;
-
- offset = pwent.pw_uid * sizeof lastlog;
-
- if (lseek (fd, offset, 0) != offset)
- return;
-
- if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog)
- memset ((char *) &lastlog, sizeof lastlog, 0);
-
- newlog = lastlog;
-
- (void) time (&newlog.ll_time);
- (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line);
- (void) lseek (fd, offset, 0);
- (void) write (fd, (char *) &newlog, sizeof newlog);
- (void) close (fd);
- }
- #endif
- SHAR_EOF
- fi
- if test -f 'mail.c'
- then
- echo shar: "will not over-write existing file 'mail.c'"
- else
- cat << \SHAR_EOF > 'mail.c'
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #include "config.h"
-
- extern char mail[];
-
- #ifdef MAILCHECK
- void mailcheck ()
- {
- struct stat statbuf;
- char *mailbox;
-
- if (mailbox = strchr (mail, '='))
- mailbox++;
- else
- return;
-
- if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
- puts ("No mail.");
- else if (statbuf.st_atime > statbuf.st_mtime)
- puts ("You have mail.");
- else
- puts ("You have new mail.");
- }
- #endif
- SHAR_EOF
- fi
- if test -f 'shadow.h'
- then
- echo shar: "will not over-write existing file 'shadow.h'"
- else
- cat << \SHAR_EOF > 'shadow.h'
- /*
- * This information is not derived from AT&T licensed sources. Posted
- * to the USENET 11/88.
- */
-
- /*
- * Shadow password security file structure.
- */
-
- struct spwd {
- char *sp_namp; /* login name */
- char *sp_pwdp; /* encrypted password */
- long sp_lstchg; /* date of last change */
- int sp_max; /* maximum number of days between changes */
- int sp_min; /* minimum number of days between changes */
- };
-
- /*
- * Shadow password security file functions.
- */
-
- struct spwd *getspent ();
- struct spwd *getspnam ();
- void setspent ();
- void endspent ();
- struct spwd *fgetspent ();
- int putspent ();
-
- #define SHADOW "/etc/shadow"
- SHAR_EOF
- fi
- if test -f 'sulog.c'
- then
- echo shar: "will not over-write existing file 'sulog.c'"
- else
- cat << \SHAR_EOF > 'sulog.c'
- #include <sys/types.h>
- #include <stdio.h>
- #include <time.h>
- #include <string.h>
- #include "config.h"
-
- extern char name[];
- extern char oldname[];
-
- time_t time ();
-
- void sulog (success)
- int success;
- {
- #ifdef SULOG
- char *tty;
- char *cp;
- char *ttyname ();
- time_t clock;
- struct tm *tm;
- struct tm *localtime ();
- FILE *fp;
-
- if ((fp = fopen (SULOG, "a+")) == (FILE *) 0)
- return; /* can't open or create logfile */
-
- (void) time (&clock);
- tm = localtime (&clock);
-
- if (isatty (0) && (cp = ttyname (0))) {
- if (tty = strrchr (cp, '/'))
- tty++;
- else
- tty = cp;
- } else
- tty = "???";
-
- (void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n",
- tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
- success ? '+':'-', tty, oldname, name);
-
- fflush (fp);
- fclose (fp);
- #endif
- }
- SHAR_EOF
- fi
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- SHELL = /bin/sh
-
- # Flags for SCO Xenix/386
- CFLAGS = -O -M3 -g -DFGETPWENT
- LIBS = -lcrypt
- LDFLAGS = -M3 -g
- LTFLAGS =
-
- # Flags for normal machines
- # CFLAGS = -O -g
- # LIBS =
- # LDFLAGS = -g
-
- LOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \
- pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o
-
- LSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \
- pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.o dialchk.o
-
- SOBJS = smain.o env.o password.o entry.o valid.o susetup.o sushell.o \
- pwent.o susub.o mail.o motd.o sulog.o shadow.o age.o
-
- SSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \
- pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c
-
- POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o
-
- PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c
-
- PWOBJS = pwconv.o pwent.o shadow.o pwage.o
-
- PWSRCS = pwconv.c pwent.c shadow.c age.c
-
- PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o
-
- PWUNSRCS = pwunconv.c pwent.c shadow.c age.c
-
- SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \
- shadow.o shell.o valid.o
-
- SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
- shadow.c shell.c valid.c
-
- FILES1 = log.c mail.c shadow.h sulog.c Makefile entry.c obscure.c \
- setup.c sub.c config.h shadow.info pmain.c sulogin.c dialup.h
-
- FILES2 = lastlog.h login.c motd.c password.c shell.c utmp.c age.c env.c \
- pwent.c shadow.c valid.c lmain.c smain.c pwconv.c dialup.c dialchk.c \
- pwunconv.c
-
- DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
- pwunconv.8
-
- all: su login pwconv pwunconv passwd sulogin
-
- lint: su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L
-
- login: $(LOBJS)
- cc -o login $(LDFLAGS) $(LOBJS) $(LIBS)
-
- login.L: $(LSRCS)
- lint $(LSRCS) > login.L
-
- su: $(SOBJS)
- cc -o su $(LDFLAGS) $(SOBJS) $(LIBS)
-
- su.L: $(SSRCS)
- lint -DSU $(SSRCS) > su.L
-
- passwd: $(POBJS)
- cc -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
-
- passwd.L: $(PSRCS)
- lint -DPASSWD $(PSRCS) > passwd.L
-
- pwconv: $(PWOBJS)
- cc -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
-
- pwconv.L: $(PWSRCS)
- lint -DPASSWD $(PWSRCS) > pwconv.L
-
- pwunconv: $(PWUNOBJS)
- cc -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
-
- pwunconv.L: $(PWUNSRCS)
- lint -DPASSWD $(PWUNSRCS) > pwunconv.L
-
- sulogin: $(SULOGOBJS)
- cc -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
-
- sulogin.L: $(SULOGSRCS)
- lint $(SULOGSRCS) > sulogin.L
-
- sushell.o: config.h shell.c
- cc -c $(CFLAGS) -DSU shell.c
- mv shell.o sushell.o
-
- susub.o: config.h sub.c
- cc -c $(CFLAGS) -DSU sub.c
- mv sub.o susub.o
-
- sulog.o: config.h
-
- susetup.o: config.h setup.c
- cc -c $(CFLAGS) -DSU setup.c
- mv setup.o susetup.o
-
- pmain.o: config.h lastlog.h shadow.h
-
- pwage.o: age.c config.h
- cp age.c pwage.c
- cc -c $(CFLAGS) -DPASSWD pwage.c
- rm pwage.c
-
- lmain.o: config.h lastlog.h
-
- setup.o: config.h
-
- utmp.o: config.h
-
- mail.o: config.h
-
- motd.o: config.h
-
- age.o: config.h
-
- log.o: config.h lastlog.h
-
- shell.o: config.h
-
- entry.o: config.h shadow.h
-
- shadow.o: shadow.h
-
- dialup.o: dialup.h
-
- dialchk.o: dialup.h config.h
-
- clean:
- -rm -f *.o a.out core npasswd nshadow
-
- clobber: clean
- -rm -f su login passwd pwconv pwunconv sulogin *.L
-
- shar: login.sh.1 login.sh.2 login.sh.3
-
- login.sh.1: $(FILES1)
- shar $(FILES1) > login.sh.1
-
- login.sh.2: $(FILES2)
- shar $(FILES2) > login.sh.2
-
- login.sh.3: $(DOCS)
- shar $(DOCS) > login.sh.3
- SHAR_EOF
- fi
- if test -f 'entry.c'
- then
- echo shar: "will not over-write existing file 'entry.c'"
- else
- cat << \SHAR_EOF > 'entry.c'
- #include <stdio.h>
- #include <pwd.h>
- #include <string.h>
- #include "config.h"
- #ifdef SHADOWPWD
- #include "shadow.h"
- #endif
-
- struct passwd *fgetpwent ();
- char *malloc ();
-
- char *strdup (s)
- char *s;
- {
- char *cp;
-
- if (s == (char *) 0)
- return ((char *) 0);
-
- if (! (cp = malloc ((unsigned) strlen (s) + 1)))
- return ((char *) 0);
-
- return (strcpy (cp, s));
- }
-
- void entry (name, pwent)
- char *name;
- struct passwd *pwent;
- {
- FILE *pwd;
- struct passwd *passwd;
- #ifdef SHADOWPWD
- struct spwd *spwd;
- char *l64a ();
- #endif
- char *cp;
-
- if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
- pwent->pw_passwd = (char *) 0;
- return;
- }
- while (passwd = fgetpwent (pwd)) {
- if (strcmp (name, passwd->pw_name) == 0)
- break;
- }
- fclose (pwd);
-
- if (passwd == (struct passwd *) 0) {
- pwent->pw_name = (char *) 0;
- pwent->pw_passwd = (char *) 0;
- } else {
- pwent->pw_name = strdup (passwd->pw_name);
- pwent->pw_uid = passwd->pw_uid;
- pwent->pw_gid = passwd->pw_gid;
- pwent->pw_comment = (char *) 0;
- pwent->pw_gecos = strdup (passwd->pw_gecos);
- pwent->pw_dir = strdup (passwd->pw_dir);
- pwent->pw_shell = strdup (passwd->pw_shell);
- #ifdef SHADOWPWD
- setspent ();
- if (spwd = getspnam (name)) {
- pwent->pw_passwd = strdup (spwd->sp_pwdp);
- if (spwd->sp_lstchg == 0) {
- pwent->pw_age = (char *) 0;
- endspent ();
- return;
- }
- pwent->pw_age = malloc (5);
- pwent->pw_age[0] = i64c (spwd->sp_max / 7);
- pwent->pw_age[1] = i64c (spwd->sp_min / 7);
- cp = l64a (spwd->sp_lstchg / 7);
- pwent->pw_age[2] = cp[0];
- pwent->pw_age[3] = cp[1];
- pwent->pw_age[4] = '\0';
- endspent ();
- return;
- }
- endspent ();
- passwd->pw_age = pwent->pw_age = (char *) 0;
- #endif
- if (passwd->pw_passwd)
- pwent->pw_passwd = strdup (passwd->pw_passwd);
-
- if (passwd->pw_age) {
- pwent->pw_age = malloc (5); /* longest legal time */
- (void) strncpy (pwent->pw_age, passwd->pw_age, 5);
- } else
- pwent->pw_age = (char *) 0;
- }
- }
- SHAR_EOF
- fi
- if test -f 'obscure.c'
- then
- echo shar: "will not over-write existing file 'obscure.c'"
- else
- cat << \SHAR_EOF > 'obscure.c'
- #include <ctype.h>
- #include "config.h"
-
- /*
- * Obscure - see if password is obscure enough.
- *
- * The programmer is encouraged to add as much complexity to this
- * routine as desired. Included are some of my favorite ways to
- * check passwords.
- */
-
- extern char pass[]; /* the new password */
- extern char orig[]; /* the original password */
- char mono[32]; /* a monocase version of pass */
-
- int obscure ()
- {
- int i;
-
- if (orig[0] == '\0')
- return (1);
-
- if (strlen (pass) < 6) { /* too short */
- printf ("Too short. ");
- return (0);
- }
- #ifdef OBSCURE
- for (i = 0;pass[i];i++)
- mono[i] = tolower (pass[i]);
-
- if (strcmp (pass, orig) == 0) /* the same */
- return (0);
-
- if (palindrome ()) /* a palindrome */
- return (0);
-
- if (caseshift ()) /* upper/lower case changes only */
- return (0);
-
- if (similiar ()) /* jumbled version of original */
- return (0);
- #endif
- return (1);
- }
-
- #ifdef OBSCURE
-
- /*
- * can't be a palindrome - like `R A D A R' or `M A D A M'
- */
-
- int palindrome ()
- {
- int i, j;
-
- i = strlen (pass);
-
- for (j = 0;j < i;j++)
- if (pass[i - j - 1] != pass[j])
- return (0);
-
- printf ("No palindromes. ");
- return (1);
- }
-
- /*
- * may not be a shifted version of original
- */
-
- int caseshift ()
- {
- int i;
-
- for (i = 0;pass[i] && orig[i];i++) {
- if (tolower (pass[i]) == tolower (orig[i]))
- continue;
- else
- return (0);
- }
- printf ("May not be case-shifted. ");
- return (1);
- }
-
- /*
- * more than half of the characters are different ones.
- */
-
- int similiar ()
- {
- int i, j;
- char *strchr ();
-
- for (i = j = 0;pass[i] && orig[i];i++)
- if (strchr (mono, tolower (orig[i])))
- j++;
-
- if (i - j > 2)
- return (0);
-
- printf ("Too similiar. ");
- return (1);
- }
- #endif
- SHAR_EOF
- fi
- if test -f 'setup.c'
- then
- echo shar: "will not over-write existing file 'setup.c'"
- else
- cat << \SHAR_EOF > 'setup.c'
- #include <sys/types.h>
- #include <pwd.h>
- #include <utmp.h>
- #include <string.h>
- #include "config.h"
-
- extern char home[];
- extern char prog[];
- extern char name[];
- extern char mail[];
-
- #ifndef SU
- extern struct utmp utent;
- #endif
-
- #ifdef QUOTAS
- long strtol ();
- long ulimit ();
- #endif
-
- void addenv ();
-
- void setup (info)
- struct passwd *info;
- {
- extern int errno;
- char logname[30];
- #ifndef SU
- char tty[30];
- #endif
- char *cp;
- int i;
- long l;
-
- #ifndef SU
- (void) strcat (strcpy (tty, "/dev/"), utent.ut_line);
- if (chown (tty, info->pw_uid, info->pw_gid) ||
- chmod (tty, TTYPERM))
- perror (tty);
- #endif
- if (chdir (info->pw_dir) == -1) {
- (void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir);
- exit (errno);
- }
- #ifdef QUOTAS
- for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) {
- if (*cp == ',')
- cp++;
-
- if (strncmp (cp, "pri=", 4) == 0) {
- i = atoi (cp + 4);
- if (i >= -20 && i <= 20)
- (void) nice (i);
-
- continue;
- }
- if (strncmp (cp, "ulimit=", 6) == 0) {
- l = strtol (cp + 6, (char **) 0, 10);
- (void) ulimit (2, l);
-
- continue;
- }
- if (strncmp (cp, "umask=", 5) == 0) {
- i = strtol (cp + 5, (char **) 0, 8) & 0777;
- (void) umask (i);
-
- continue;
- }
- }
- #endif
- if (setgid (info->pw_gid) == -1) {
- puts ("Bad group id");
- exit (errno);
- }
- if (setuid (info->pw_uid) == -1) {
- puts ("Bad user id");
- exit (errno);
- }
- (void) strcat (strcpy (home, "HOME="), info->pw_dir);
- addenv (home);
-
- if (info->pw_shell == (char *) 0)
- info->pw_shell = "/bin/sh";
-
- (void) strcat (strcpy (prog, "SHELL="), info->pw_shell);
- addenv (prog);
-
- if (info->pw_uid == 0)
- addenv (SUPATH);
- else
- addenv (PATH);
-
- #ifndef SU
- (void) strcat (strcpy (logname, "LOGNAME="), name);
- addenv (logname);
- #endif
- (void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
- addenv (mail);
- }
- SHAR_EOF
- fi
- if test -f 'sub.c'
- then
- echo shar: "will not over-write existing file 'sub.c'"
- else
- cat << \SHAR_EOF > 'sub.c'
- #include <sys/types.h>
- #include <pwd.h>
- #include <utmp.h>
- #include <string.h>
-
- extern struct passwd pwent;
- #ifndef SU
- extern struct utmp utent;
- #endif
-
- void setutmp ();
-
- /*
- * I have heard of two different types of behavior with subsystem roots.
- * One has you execute login no matter what. The other has you execute
- * the command [ if one exists ] after the '*' in the shell name. The
- * macro SUBLOGIN says to execute /bin/login [ followed by /etc/login ]
- * regardless. Otherwise, pwent.pw_shell is fixed up and that command
- * is executed [ by returning to the caller ]. I prefer the latter since
- * it doesn't require having a "login" on the new root filesystem.
- */
-
- void subsystem ()
- {
- char *strdup ();
-
- if (chdir (pwent.pw_dir) || chroot (pwent.pw_dir)) {
- printf ("Can't change to \"%s\"\n", pwent.pw_dir);
- exit (1);
- }
- #ifndef SU
- (void) strcpy (utent.ut_line, "<!sublogin>");
-
- setutmp ();
- #endif
- #ifdef SUBLOGIN
- execl ("/bin/login", "login", name, (char *) 0);
- execl ("/etc/login", "login", name, (char *) 0);
- puts ("No /bin/login or /etc/login on root");
- exit (1);
- #else
- if (pwent.pw_shell[1] == '\0')
- pwent.pw_shell = "/bin/sh";
- else
- pwent.pw_shell++;
- #endif
- }
- SHAR_EOF
- fi
- if test -f 'config.h'
- then
- echo shar: "will not over-write existing file 'config.h'"
- else
- cat << \SHAR_EOF > 'config.h'
- /*
- * Configuration file for login.
- */
-
- /*
- * Define DIALUP to use dialup password files
- */
-
- #define DIALUP
-
- /*
- * Define SHADOWPWD to use shadow [ unreadable ] password file
- */
-
- #define SHADOWPWD
-
- /*
- * Define OBSCURE to include hard password testing code.
- */
-
- #define OBSCURE
-
- /*
- * Define PASSLENGTH to be shortest legal password
- */
-
- #define PASSLENGTH 5
-
- /*
- * Define NOBLANK if you want all passwords prompted for, including
- * empty ones.
-
- #undef NOBLANK
-
- /*
- * Define NDEBUG for production versions
- */
-
- #define NDEBUG
-
- /*
- * Define HZ if login must set HZ value
- */
-
- #define HZ "HZ=50"
-
- /*
- * Define TZ if login must set timezone
- */
-
- #define TZ "TZ=CST6CDT"
-
- /*
- * Define the default PATH and SUPATH here. PATH is for non-privileged
- * users, SUPATH is for root.
- */
-
- #define PATH "PATH=:/bin:/usr/bin"
- #define SUPATH "PATH=:/bin:/usr/bin:/etc"
-
- /*
- * Define the mailbox directory
- */
-
- #define MAILDIR "/usr/spool/mail/"
-
- /*
- * Define AGING if you want the password aging checks made.
- */
-
- #define AGING
-
- /*
- * Define MAILCHECK if you want the mailbox checked for new mail
- *
- * One of two messages are printed - `You have new mail.' or
- * `You have mail.'.
- */
-
- #define MAILCHECK
-
- /*
- * Define CONSOLE if you want ROOT restricted to a single terminal
- */
-
- #define CONSOLE "tty01"
-
- /*
- * Define MOTD if you want the message of the day (/etc/motd) printed
- * at login time.
- */
-
- #define MOTD
-
- /*
- * Define HUSHLOGIN if you want the code added to avoid printing the
- * motd if a file $HOME/.hushlogin exists. This obviously only matters
- * if MOTD is #define'd.
- */
-
- #define HUSHLOGIN
-
- /*
- * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog.
- */
-
- #define LASTLOG
-
- /*
- * Define TTYPERM to be the initial terminal permissions. Defining
- * as 0600 will not allow messages, 0622 will.
- */
-
- #define TTYPERM 0600
-
- /*
- * Define QUOTAS if you want the code added in setup.c to support
- * file ulimit and nice [ and umask as well ] setting from the password
- * file.
- */
-
- #define QUOTAS
-
- /*
- * Define file name for sulog. If SULOG is not defined, there will be
- * no logging. This is NOT a good idea ... We also define other file
- * names.
- */
-
- #define SULOG "/usr/adm/sulog"
- #define PWDFILE "/etc/passwd"
- #define OPWDFILE "/etc/-passwd"
- #define NPWDFILE "/etc/npasswd"
- #define OSHADOW "/etc/-shadow"
- #define NSHADOW "/etc/nshadow"
-
- /*
- * Define PWDLOCK to be a locking semaphore for updating the password
- * file.
- */
-
- #define PWDLOCK "/etc/.pwdlock"
- SHAR_EOF
- fi
- if test -f 'shadow.info'
- then
- echo shar: "will not over-write existing file 'shadow.info'"
- else
- cat << \SHAR_EOF > 'shadow.info'
- >From vector!killer!osu-cis!att!cuuxb!dlm Sun Nov 13 08:11:08 CST 1988
- Article 5025 of comp.unix.wizards:
- Path: rpp386!vector!killer!osu-cis!att!cuuxb!dlm
- >From: dlm@cuuxb.ATT.COM (Dennis L. Mumaugh)
- Newsgroups: comp.unix.wizards
- Subject: /etc/shadow
- Summary: See release notes for SVR3.2
- Keywords: shadow password
- Message-ID: <2189@cuuxb.ATT.COM>
- Date: 11 Nov 88 21:33:37 GMT
- References: <16722@agate.BERKELEY.EDU> <2178@cuuxb.ATT.COM> <16768@agate.BERKELEY.EDU> <17828@glacier.STANFORD.EDU> <2182@cuuxb.ATT.COM> <8
- Reply-To: dlm@cuuxb.UUCP (Dennis L. Mumaugh)
- Organization: ATT Data Systems Group, Lisle, Ill.
- Lines: 60
-
- In article <8861@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
- >It would be a great service to the community if specifications for
- >this feature were posted or at least sent to developers who want
- >to enable a similar feature on their (typically BSD-based) systems.
- >For example, what is the shadow file called, what is its format,
- >what sort of stuff is left in the password field in /etc/passwd,
- >what facilities are there to validate a password against the
- >shadow encrypted password file?
-
- The documentation is scattered in the Release Notes for System V
- Release 3.2. Of course they don't have a page shadow(4) but:
-
- The file is /etc/shadow and is owned by root and mode 400.
- It contains one line per login. Fields are separated by colons:
- username \- users login name
- password \- A 13 character encrypted password or a lock string to
- indicater the login is not accessible
- lastchanged \- number of days since January 1, 1970 that the password
- has been modified
- min \- the number of days required between password changes
- max \- the maximum number of days the password is valid.
-
- Routines to work with /etc/shadow:
- #include <shadow.h>
- struct spwd *getspent();
- struct spwd *getspnam(char * name);
- void setspent();
- void endspent();
- struct spwd *fgetspent(FILE *fp);
- int putspent(struct spwd *p,FILE *fp);
-
- Programs allied with this are
- pwconv \- install and/or update /etc/shadow with information
- from /etc/passwd
- pwunconv \- restore /etc/password from /etc/shadown
-
- Programs like login, su and passwd work with either /etc/passwd
- ONLY or with the added /etc/shadow. If there is no entry in
- /etc/shadow we accept the /etc/passwd as gospel [in case someone
- forgot to run /usr/lib/pwconv after adding a user.]
-
- Also /usr/include/shadow.h:
-
- struct spwd {
- char *sp_namp; /* users login name */
- char *sp_pwdp; /* encrypted password */
- long sp_lstchg; /* number of days since January 1, 1970
- that the password has been modified */
- int sp_max; /* the number of days required between password changes */
- int sp_min; /* the maximum number of days the password is valid. */
- }
- #define SHADOW "/etc/shadow"
-
- ATT doesn't provide any of the functions or the header file as
- part of its product. It is in the source but not the binary.
- Thus developers who need the routines must contact their ATT
- person [not me!] to obtain the shadow password security library
- --
- =Dennis L. Mumaugh
- Lisle, IL ...!{att,lll-crg}!cuuxb!dlm OR cuuxb!dlm@arpa.att.com
-
-
- SHAR_EOF
- fi
- if test -f 'pmain.c'
- then
- echo shar: "will not over-write existing file 'pmain.c'"
- else
- cat << \SHAR_EOF > 'pmain.c'
- #include <sys/types.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <errno.h>
- #include <string.h>
- #include "config.h"
- #include "lastlog.h"
- #include "shadow.h"
-
- char name[BUFSIZ];
- char orig[BUFSIZ];
- char pass[BUFSIZ];
- char pass2[BUFSIZ];
-
- struct passwd pwent;
-
- #ifndef RETRIES
- #define RETRIES 3
- #endif
-
- char *l64a ();
- char *crypt ();
- extern int errno;
- long a64l ();
- void entry ();
- time_t time ();
-
- int main (argc, argv)
- int argc;
- char **argv;
- {
- char *cp;
- char *getlogin ();
- int amroot;
- int lockfd = -1;
- #ifdef OBSCURE
- int force = 0;
- #endif
- int retries;
- #ifdef AGING
- long week;
- long lastweek;
- #endif
- long salttime;
- struct passwd *pw;
- struct passwd *getpwuid ();
- struct passwd *sgetpwent ();
- FILE *npwd;
- #ifdef SHADOWPWD
- struct spwd *spwd;
- struct spwd tspwd;
- #else
- FILE *pwd;
- char buf[BUFSIZ];
- #endif
-
- argc--; argv++; /* shift ... */
-
- if (! (pw = getpwuid (getuid ())))
- goto failure; /* can't get my name ... */
-
- #ifdef OBSCURE
- if (argc > 0 && strcmp (argv[0], "-f") == 0) {
- force = 1;
- argc--; argv++; /* shift ... */
- }
- #endif
- if (argc > 0)
- (void) strcpy (name, argv[0]);
- else if (cp = getlogin ()) /* need user name */
- (void) strcpy (name, cp);
- else /* can't find user name! */
- goto failure;
-
- printf ("Changing password for %s\n", name);
-
- amroot = getuid () == 0; /* currently am super user */
- if (! amroot)
- force = 0;
-
- if (! amroot && strcmp (name, pw->pw_name) != 0)
- goto failure;
-
- entry (name, &pwent); /* get password file entry */
-
- if (! pwent.pw_name) /* no entry for user??? */
- goto failure;
-
- if (! amroot) {
- if (! password ("Old Password:", orig))
- exit (1);
-
- if (! valid (orig, &pwent)) {
- puts ("Sorry.");
- exit (1);
- }
- }
- #ifdef AGING
- if (! amroot && pwent.pw_age) { /* check out the age */
- #ifdef SHADOWPWD
- (void) time (&week);
- week /= (24L * 60L * 60L); /* days since epoch */
- if (spwd = getspnam (name)) { /* use entries in shadow */
- if (spwd->sp_min > spwd->sp_max) {
- puts ("You may not change this password");
- exit (1);
- }
- if (spwd->sp_lstchg + spwd->sp_min > week) {
- printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
- exit (1);
- }
- } else {
- #endif /* SHADOWPWD */
- (void) time (&week);
- week /= (7L * 24L * 60L * 60L); /* weeks since epoch */
- lastweek = a64l (&pwent.pw_age[2]);
-
- if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
- puts ("You may not change this password");
- exit (1);
- }
- if (c64i (pwent.pw_age[1]) + lastweek > week) {
- printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
- exit (1);
- }
- #ifdef SHADOWPWD
- }
- #endif
- }
- #endif
- printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
- #ifdef OBSCURE
- puts ("Please use a combination of upper and lowercase letters and numbers");
- #endif
- retries = RETRIES;
- retry:
- if (! password ("New Password:", pass))
- exit (1);
-
- if (!force && ! obscure ()) {
- #ifdef OBSCURE
- puts ("Password not changed.");
- exit (1);
- #else
- if (retries-- > 0) {
- puts ("Please try again.");
- goto retry;
- } else
- goto toomany;
- #endif
- }
- if (! password ("Re-enter new password:", pass2))
- exit (1);
-
- if (strcmp (pass, pass2) != 0) {
- puts ("They don't match; try again");
-
- if (retries-- > 0)
- goto retry;
- else
- goto toomany;
- }
- #ifdef AGING
- if (pwent.pw_age) {
- cp = l64a (week);
-
- pwent.pw_age[2] = cp[0];
- pwent.pw_age[3] = cp[1];
- pwent.pw_age[4] = '\0';
- }
- #endif
- (void) time (&salttime);
- salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
- pwent.pw_passwd = crypt (pass, l64a (salttime));
-
- /*
- * Now we get to race the bad guy. I don't think he can get us.
- *
- * Ignore most reasonable signals.
- * Maybe we should ignore more? He can't hurt us until the end.
- *
- * Get a lock file.
- *
- * Copy first part of password file to new file.
- * Illegal lines are copied verbatim.
- * File permissions are r--r--r--, owner root, group root.
- *
- * Output the new entry.
- * Only fields in struct passwd are output.
- *
- * Copy the rest of the file verbatim.
- *
- * Rename (link, unlink) password file to backup.
- * Kill me now and nothing changes or no one gets in.
- *
- * Rename (link, unlink) temporary file to password file.
- * Kill me now and no one gets in or lock is left.
- *
- * Remove locking file.
- *
- * That's all folks ...
- */
-
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
- signal (SIGTERM, SIG_IGN);
-
- umask (0); /* get new files modes correct */
- #ifndef NDEBUG
- if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #else
- if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #endif /* NDEBUG */
- {
- puts ("Can't get lock");
- exit (1);
- }
- umask (077); /* close security holes to come ... */
- #ifdef SHADOWPWD
- if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
- goto failure;
-
- if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
- goto failure;
-
- if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
- goto failure;
-
- setspent ();
-
- while (spwd = getspent ()) {
- if (strcmp (spwd->sp_namp, name) == 0)
- break;
-
- (void) putspent (spwd, npwd);
- }
- if (spwd == (struct spwd *) 0) { /* didn't find a match */
- spwd = &tspwd; /* use a local structure instead */
- spwd->sp_namp = pwent.pw_name;
- spwd->sp_max = 10000; /* about as big as possible */
- spwd->sp_min = 0; /* about as small as possible */
- }
- spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
-
- (void) time (&lastweek); /* get the current time ... */
- lastweek /= (24L*60L*60L); /* ... turn it into days. */
- spwd->sp_lstchg = lastweek; /* save it as date of last change */
-
- (void) putspent (spwd, npwd); /* add the new entry */
-
- while (spwd = getspent ()) /* finish the other ones off */
- (void) putspent (spwd, npwd);
-
- endspent ();
-
- if (ferror (npwd)) {
- perror (NSHADOW);
- if (unlink (NPWDFILE) || unlink (PWDLOCK))
- fputs ("Help!\n", stderr);
-
- exit (1);
- }
- fflush (npwd);
- fclose (npwd);
-
- if (access (OSHADOW, 0) == 0) {
- if (unlink (OSHADOW)) {
- puts ("Can't remove backup file");
- goto unlock;
- }
- }
- if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
- puts ("Can't save backup file");
- goto unlock;
- }
- if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) {
- (void) unlink (OSHADOW);
- puts ("Can't rename new file");
- goto unlock;
- }
- if (unlink (OSHADOW)) {
- puts ("Can't remove backup file");
- goto unlock;
- }
- #else /* ! SHADOWPWD */
- if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
- goto failure;
-
- #ifndef NDEBUG
- if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
- #else
- umask (077); /* no permissions for non-roots */
-
- if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
- #endif /* NDEBUG */
- goto failure;
-
- #ifndef NDEBUG
- chmod (NPWDFILE, 0444); /* lets have some security here ... */
- chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */
- #endif /* NDEBUG */
- if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
- goto failure;
-
- while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
- if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
- fputs (buf, npwd);
- } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
- fputs (buf, npwd);
- else
- break;
- }
- (void) fprintf (npwd, "%s:", pw->pw_name);
- if (pwent.pw_age)
- (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
- else
- (void) fprintf (npwd, "%s:", pwent.pw_passwd);
-
- (void) fprintf (npwd, "%d:%d:%s:%s:%s",
- pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir
- pwent.pw_shell ? pwent.pw_shell:"");
-
- while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
- fputs (buf, npwd);
-
- if (ferror (npwd)) {
- perror (NPWDFILE);
- if (unlink (NPWDFILE) || unlink (PWDLOCK))
- fputs ("Help!\n", stderr);
-
- exit (1);
- }
- fflush (npwd);
- fclose (npwd);
- #ifdef NDEBUG
- if (unlink (OPWDFILE) == -1) {
- if (errno != ENOENT) {
- puts ("Can't unlink backup file");
- goto unlock;
- }
- }
- if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
- puts ("Can't save backup file");
- goto unlock;
- }
- if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) {
- puts ("Can't rename new file");
- goto unlock;
- }
- #endif /* NDEBUG */
- #endif /* SHADOW */
- #ifndef NDEBUG
- (void) unlink (".pwdlock");
- #else
- (void) unlink (PWDLOCK);
- #endif
- exit (0);
- /*NOTREACHED*/
-
- failure:
- puts ("Permission denied.");
- unlock:
- if (lockfd >= 0)
- (void) unlink (PWDLOCK);
-
- (void) unlink (NPWDFILE);
- exit (1);
- /*NOTREACHED*/
-
- toomany:
- puts ("Too many tries; try again later.");
- exit (1);
- /*NOTREACHED*/
- }
- SHAR_EOF
- fi
- if test -f 'sulogin.c'
- then
- echo shar: "will not over-write existing file 'sulogin.c'"
- else
- cat << \SHAR_EOF > 'sulogin.c'
- #include <sys/types.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <utmp.h>
- #include "config.h"
- #include "lastlog.h"
-
- char name[BUFSIZ];
- char pass[BUFSIZ];
- char home[BUFSIZ];
- char prog[BUFSIZ];
- char mail[BUFSIZ];
-
- struct passwd pwent;
- struct utmp utent;
- struct lastlog lastlog;
-
- #ifndef MAXENV
- #define MAXENV 64
- #endif
-
- char *newenvp[MAXENV];
- int newenvc = 0;
- int maxenv = MAXENV;
- extern char **environ;
-
- #ifndef ALARM
- #define ALARM 60
- #endif
-
- #ifndef RETRIES
- #define RETRIES 3
- #endif
-
- int main (argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
- {
- char *getenv ();
- char *ttyname ();
- char *cp;
-
- if (access (PWDFILE, 0) == -1) { /* must be a password file! */
- printf ("No password file\n");
- exit (1);
- }
- #ifndef DEBUG
- if (getppid () != 1) /* parent must be INIT */
- exit (1);
- #endif
- if (! isatty (0)) /* must be a terminal */
- exit (1);
-
- while (*envp) /* add inherited environment, */
- addenv (*envp++); /* some variables change later */
-
- #ifdef TZ
- addenv (TZ); /* set the default $TZ, if one */
- #endif
- #ifdef HZ
- addenv (HZ); /* set the default $HZ, if one */
- #endif
- (void) strcpy (name, "root"); /* KLUDGE!!! */
-
- while (1) { /* repeatedly get login/password pairs */
- entry (name, &pwent); /* get entry from password file */
- if (pwent.pw_name == (char *) 0) {
- printf ("No password entry for 'root'\n");
- exit (1);
- }
-
- /*
- * Here we prompt for the root password, or if no password is
- * given we just exit and let INIT go to runlevel 2.
- */
-
- /* get a password for root */
- if (! password ("Type control-d for normal startup,\n(or give root password for system maintenance):", pass))
- exit (0);
-
- if (valid (pass, &pwent)) /* check encrypted passwords ... */
- break; /* ... encrypted passwords matched */
-
- puts ("Login incorrect");
- }
- environ = newenvp; /* make new environment active */
-
- puts ("Entering System Maintenance Mode");
-
- /*
- * Normally there would be a utmp entry for login to mung on
- * to get the tty name, date, etc. from. We don't need all that
- * stuff because we won't update the utmp or wtmp files. BUT!,
- * we do need the tty name so we can set the permissions and
- * ownership.
- */
-
- if (cp = ttyname (0)) /* found entry in /dev/ */
- strcpy (utent.ut_line, cp); /* needed for tty perms (setup) */
-
- if (getenv ("IFS")) /* don't export user IFS ... */
- addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */
-
- setup (&pwent); /* set UID, GID, HOME, etc ... */
-
- shell (pwent.pw_shell); /* exec the shell finally. */
- /*NOTREACHED*/
- }
- SHAR_EOF
- fi
- if test -f 'dialup.h'
- then
- echo shar: "will not over-write existing file 'dialup.h'"
- else
- cat << \SHAR_EOF > 'dialup.h'
- /*
- * Structure of d_passwd file
- *
- * The d_passwd file contains the names of login shells which require
- * dialup passwords. Each line contains the fully qualified path name
- * for the shell, followed by an optional password. Each field is
- * separated by a ':'.
- *
- * Structure of the dialups file
- *
- * The dialups file contains the names of ports which may be dialup
- * lines. Each line consists of the last component of the path
- * name. Any leading directory names are removed.
- */
-
- struct dialup {
- char *du_shell;
- char *du_passwd;
- };
-
- void setduent ();
- void endduent ();
- struct dialup *getduent ();
- struct dialup *getdushell ();
-
- #define DIALPWD "/etc/d_passwd"
- #define DIALUPS "/etc/dialups"
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
-